package org.leumasjaffe.initiativeTracker.operator;


import java.util.ArrayList;

import org.eclipse.jdt.annotation.NonNullByDefault;
import org.leumasjaffe.initiativeTracker.Constants;
import org.leumasjaffe.initiativeTracker.entity.Character;
import org.leumasjaffe.initiativeTracker.entity.CharacterList;
import org.leumasjaffe.initiativeTracker.entity.NPC;
import org.leumasjaffe.initiativeTracker.entity.PC;
import org.leumasjaffe.initiativeTracker.entity.Trap;
import org.leumasjaffe.initiativeTracker.view.InitiativeFrame;

import tools.Pair;
import org.leumasjaffe.util.array.Swap;
import org.leumasjaffe.util.io.PortableScanner;

/**
 * Main wrapper for computing data and holding associated classes
 *  for the initiative tracker program
 * @author Sam Jaffe
 *
 */
@NonNullByDefault
public class UnitManager{
	
	public final CharacterList list;
	public final InitiativeController tracker;
	public final CharacterGenerator gen;
	
	private ArrayList<Pair<Double, Trap>> traps;
			
	private int num = 1;
	private int death;
	private int turnNum;
	private int subTurn;
	
	/**
	 * Constructor for the UnitManager class
	 */
	@SuppressWarnings("null")
	UnitManager(InitiativeController tracker) {	
		this.tracker = tracker;
		this.list = tracker.list;
		if (Constants.isDM) {
			this.gen = new CharacterGenerator(tracker);
				if (Constants.client)
					this.traps = TrapImporter.importTraps(tracker.id);
		}
		else
			this.gen = null;
	}

	/**
	 * Checks to see if any traps are triggered
	 */
	public void checkTraps() {
		double frac = 1.0/this.list.size();
	    double uBound = this.subTurn*frac;
		double lBound = uBound-frac;
		if (this.traps != null)
			for (Pair<Double, Trap> p : this.traps) {
				double pos = p.getT();
				if (pos <= uBound || pos > lBound || (pos == 0 && this.subTurn == 0))
					p.getS().listAilments();
			}
	}

	/**
	 * Method to generate a new Character
	 * @return 
	 */
	@SuppressWarnings("null")
	public Character startup() {
		Character c = this.gen.createChar();
		int roll = this.tracker.rollInit(c);
		this.list.insert(new CharacterLinker(c, this.tracker.id));
		for (int n = 1; n < this.num; n++) {
			Character b = this.gen.remake(c);
			if (Constants.uniAct)
				b.setInit(roll);
			else
				this.tracker.rollInit(b);
			this.list.insert(new CharacterLinker(b, this.tracker.id));
		}
		this.num = 1;
		PortableScanner.nextLine();
		return c;
	}

	/**
	 * A method to allow a Character to delay their actions until later
	 */
	public void delay() {
		CharacterLinker a = this.list.get(this.subTurn);
		CharacterLinker b;
		int size1 = this.list.size()-1-this.subTurn;
		if (0 < size1) {
			int x = 1;
			do {
				b = this.list.get(this.subTurn+x++);
			} while (b.getCharacter().isDelayed() && x < size1);
			x--;
			
			a.tearDown();
			b.tearDown();

//			this.list.set(this.subTurn+x, a);
//			this.list.set(this.subTurn, b);
			
			Swap.swap(this.list.getList(), this.subTurn, this.subTurn+x);

			Character ac = a.getCharacter();
			
			b.update(this.subTurn);
			a.update(this.subTurn+x);
			
			changeTurn();
			
			ac.setHp(ac.getHp() + ac.getDot());
			ac.checkDelayed();
		}
	}

	/**
	 * Kills all NonPlayerCharacters (NPC) in the allPieces array
	 */
	public void killAll() {
		for (int i = 0; i < this.list.size(); i++) {
			CharacterLinker cl = this.list.get(i);
			Character c = cl.getCharacter();
			if (c instanceof NPC) {
				cl.tearDown();
				this.list.remove(cl);
				cl = null;
			}
			else {
				((PC) c).nullTemp();
				c.setDot(0);
			}
		}
		
		if (Constants.client)
			for (int x = 0; x < InitiativeFrame.pageLength; x++)
				this.list.get(x).update(x);		
	}

	/**
	 * A function to change turns to the next Character in allPieces
	 */
	public void changeTurn() {
		if (Constants.isDM && Constants.client)
			checkTraps();

		if (this.list.size() > this.subTurn) {
			CharacterLinker c = this.list.get(this.subTurn);
			if (c.bleed()) {
				c.listAilments();
				if (Constants.client && InitiativeFrame.onPage(this.subTurn))
					c.update(this.subTurn - (Constants.pageNum * InitiativeFrame.pageLength));

			}
			else {
				c.tearDown();
				this.list.remove(c);
				rebuild();
				changeTurn();
			}
		}
	}

	/**
	 * A method to shift all characters into their correct slots after one or more is removed
	 */
	public void rebuild() {
		this.subTurn -= this.death;
		this.death = 0;
		if (Constants.client)
			InitiativeFrame.getInstance().repage();
	}
	
	public void addDeath(int index) {
		if (index < this.subTurn)
			this.death++;
	}

	/**
	 * 
	 */
	public void nextTurn() {
		if (this.subTurn >= this.list.size()-1) {
			this.subTurn = 0;
			this.turnNum += 1;
			System.out.println("\nTurn " + (this.turnNum - 1) + 
						" is over, beginning turn " + this.turnNum);
		}
		else
			this.subTurn += 1;
		changeTurn();
	}
	
	public int getNum() {
		return this.num;
	}

	public void setNum(int num) {
		this.num = num;
	}
	
	/**
	 * @return the turnNum
	 */
	public int getTurnNum() {
		return this.turnNum;
	}

	/**
	 * @param turnNum the turnNum to set
	 */
	public void setTurnNum(int turnNum) {
		this.turnNum = turnNum;
	}
	
	/**
	 * @return the subTurn
	 */
	public int getSubTurn() {
		return this.subTurn;
	}

	/**
	 * @param subTurn the subTurn to set
	 */
	public void setSubTurn(int subTurn) {
		this.subTurn = subTurn;
	}
			
}
